import "gl-matrix";
import { mat4, vec3, vec4 } from "gl-matrix";
let gl: WebGLRenderingContext = null;
let canvas: HTMLCanvasElement = null;
var elapsedTime: number = 0;
var lastRenderTime: number = 0;
let textureHandle: WebGLTexture = null;
let textureHandle1: WebGLTexture = null;
let vec: number = 1;
let anmiTime: number = 1;
let uniformAnim: WebGLUniformLocation = 0;
// 准备WebGL的绘制上下文
function prepare() {
  window.document.title = "多纹理";
  canvas = document.createElement("canvas");
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  canvas.style.position = "absolute";
  canvas.style.width = "" + canvas.width;
  canvas.style.height = "" + canvas.height;
  document.body.append(canvas);
  gl = canvas.getContext("webgl");
  lastRenderTime = new Date().getTime();
}

// 准备WebGL需要使用的素材
function webglPrepare() {
  prepareVertexData();
  createProgram();
}

var vertexData: WebGLBuffer;
function prepareVertexData() {
  // Prepare Vertex Data
  let vertices = [
    0,
    0,
    0,
    0.0,
    0.0, //1
    400,
    0,
    0,
    1.0,
    0.0, //2
    400,
    400,
    0,
    1.0,
    1.0, //3

    0,
    0,
    0,
    0.0,
    0.0, //4
    400,
    400,
    0,
    1.0,
    1.0, //5
    0,
    400,
    0,
    0.0,
    1.0, //6
  ];

  // 在GPU上为顶点数据开辟空间
  vertexData = gl.createBuffer();
  // 将上面开辟的空间进入编辑模式
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexData);
  // 向上面开辟的空间写入数据
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
  textureHandle = initTexture("./back.jpg");
  textureHandle1 = initTexture("./fog.png");
}
function handleLoadedTexture(texture: WebGLTexture, image: HTMLImageElement) {
  //绑定纹理
  gl.bindTexture(gl.TEXTURE_2D, texture);
  /**
   * 1.
   * 2.
   * 3.纹理采用rgba
   * 4.image 的格式为rgba
   */
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
  //用于定义大于或小于真实尺寸时的图片算法，NEAREST效率高，LINEAR效率低但效果好，图片较小时看不出差别
  gl.texParameteri(
    gl.TEXTURE_2D,
    gl.TEXTURE_MAG_FILTER,
    //gl.NEAREST//最近点采样
    gl.LINEAR
  ); //小图贴大面
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); //大图贴小面
  //纹理包装
  /**
   * CLAMP_TO_EDGE用边缘像素填充
   * REPEAT 重复
   * MIRRORED_REPEAT 镜像
   */
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  gl.bindTexture(gl.TEXTURE_2D, null);
}
/**
 *
 * @param {string} imageFile 文件路径
 */
function initTexture(imageFile: string) {
  const textureHandle: WebGLTexture = gl.createTexture();
  const image: HTMLImageElement = new Image();
  image.src = imageFile;
  image.onload = function () {
    handleLoadedTexture(textureHandle, image);
  };
  return textureHandle;
}
var program: WebGLProgram;
var vertexShader: WebGLShader;
var fragmentShader: WebGLShader;
let vertexShaderCode =
  "precision lowp float;" +
  "attribute vec3 position;" +
  "attribute vec2 inUV;" +
  "uniform mat4 projection;" +
  "varying vec2 outUV;" +
  "void main() {" +
  "gl_Position = projection * vec4(position,1.0);" +
  "outUV = inUV;" +
  "}";
let fragmentShaderCode =
  "precision mediump float;" +
  "uniform sampler2D texture;" +
  "uniform sampler2D texture1;" +
  "uniform float anim;" +
  "varying vec2 outUV;" +
  "void main() {" +
  "vec4 color0=texture2D(texture,outUV);" +
  "vec4 color1=texture2D(texture1,vec2(outUV.x+anim,outUV.y));"+
  "gl_FragColor = color0*color1;" +
  "}";

function createProgram() {
  program = gl.createProgram();

  vertexShader = compileShader(vertexShaderCode, gl.VERTEX_SHADER);
  fragmentShader = compileShader(fragmentShaderCode, gl.FRAGMENT_SHADER);
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);

  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    console.log(
      "Unable to initialize the shader program: " +
        gl.getProgramInfoLog(program)
    );
  }
  return program;
}

function compileShader(shaderSrc: string, shaderType: number): WebGLShader {
  let shader = gl.createShader(shaderType);
  gl.shaderSource(shader, shaderSrc);
  gl.compileShader(shader);
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    console.log(
      "An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader)
    );
    gl.deleteShader(shader);
    return null;
  }
  return shader;
}

function render() {
  let now = new Date().getTime();
  let delta = now - lastRenderTime;
  lastRenderTime = now;
  elapsedTime += delta;

  gl.viewport(0, 0, canvas.width, canvas.height);
  gl.clearColor(0, 0, 0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);

  gl.useProgram(program);
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexData);
  let positionLoc: GLint = gl.getAttribLocation(program, "position");
  gl.enableVertexAttribArray(positionLoc);
  gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 4 * 5, 0);
  //位移
  anmiTime += vec * 0.01;
  uniformAnim = gl.getUniformLocation(program, "anim");
  gl.uniform1f(uniformAnim, anmiTime);
  let projection: mat4 = mat4.create();
  mat4.ortho(projection, 0, 800, 600, 0, -100, 100);
  let uniformLoc = gl.getUniformLocation(program, "projection");
  gl.uniformMatrix4fv(uniformLoc, false, projection);
  //贴图
  let uniformTexture: WebGLUniformLocation = gl.getUniformLocation(
    program,
    "texture"
  );
  gl.activeTexture(gl.TEXTURE0); //激活纹理 第0阶段
  gl.bindTexture(gl.TEXTURE_2D, textureHandle);
  gl.uniform1i(uniformTexture, 0); //shader到第0阶段取纹理
  //纹理2
  let uniformTexture1: WebGLUniformLocation = gl.getUniformLocation(
    program,
    "texture1"
  );
  gl.activeTexture(gl.TEXTURE1);
  gl.bindTexture(gl.TEXTURE_2D, textureHandle1);
  gl.uniform1f(uniformTexture1, 1);
  let attrUv: GLint = gl.getAttribLocation(program, "inUV");
  gl.enableVertexAttribArray(attrUv);
  gl.vertexAttribPointer(attrUv, 2, gl.FLOAT, false, 4 * 5, 12);

  gl.drawArrays(gl.TRIANGLES, 0, 6);

  requestAnimationFrame(render);
}

window.onload = () => {
  // 主流程
  prepare();
  webglPrepare();
  render();
};
